load("//:build/kj_test.bzl", "kj_test")
load("//:build/wd_capnp_library.bzl", "wd_capnp_library")
load("//:build/wd_cc_embed.bzl", "wd_cc_embed")
load("//:build/wd_cc_library.bzl", "wd_cc_library")
load("//:build/wd_test.bzl", "wd_test")

# TODO(cleanup): Split up into smaller targets, although this target is already relatively small and
# not encumbered with many dependencies.
wd_cc_library(
    name = "io-helpers",
    srcs = [
        "io-thread-context.c++",
        "io-timers.c++",
        "request-tracker.c++",
    ],
    hdrs = [
        "io-thread-context.h",
        "io-timers.h",
        "request-tracker.h",
    ],
    visibility = ["//visibility:public"],
    deps = [
        "//src/workerd/jsg",
        "@capnp-cpp//src/capnp/compat:http-over-capnp",
    ],
)

wd_cc_library(
    name = "trace-stream",
    srcs = ["trace-stream.c++"],
    hdrs = ["trace-stream.h"],
    implementation_deps = [
        "//src/workerd/util:completion-membrane",
        "//src/workerd/util:strings",
        "//src/workerd/util:uuid",
    ],
    visibility = ["//visibility:public"],
    deps = [
        ":io",
        "//src/workerd/util:checked-queue",
    ],
)

wd_cc_library(
    name = "io",
    # HACK: Currently, the `io` and `api` packages are interdependent. We fold all the sources
    #   from `api` into `io`. In principle, it should be possible to pull them apart so `api`
    #   depends on `io` but not vice versa. In practice, this appears very difficult due to the
    # IoContext -> Worker -> ServiceWorkerGlobalScope -> (various api targets) dependency chain.
    # TODO(cleanup): Fix this.
    srcs = [
        "compatibility-date.c++",
        "features.c++",
        "hibernation-manager.c++",
        "io-channels.c++",
        "io-context.c++",
        "io-own.c++",
        "io-util.c++",
        "tracer.c++",
        "worker.c++",
        "worker-fs.c++",
    ] + ["//src/workerd/api:srcs"],
    hdrs = [
        "compatibility-date.h",
        "features.h",
        "hibernation-manager.h",
        "io-channels.h",
        "io-context.h",
        "io-own.h",
        "io-util.h",
        "tracer.h",
        "worker.h",
        "worker-fs.h",
    ] + ["//src/workerd/api:hdrs"],
    # global CPU-specific options are inconvenient to specify with bazel – just set the options we
    # need for CRC32C in this target for now.
    copts = select({
        "@platforms//cpu:aarch64": [
            "-mcrc",
        ],
        "@platforms//cpu:x86_64": [
            "-msse4.2",
        ],
    }),
    implementation_deps = [
        "//src/workerd/api:crypto-crc-impl",
        "//src/workerd/api:data-url",
        "//src/workerd/api/node:exceptions",
        "//src/workerd/util:completion-membrane",
        "//src/workerd/util:entropy",
        "//src/workerd/util:perfetto",
        "//src/workerd/util:string-buffer",
        "//src/workerd/util:uuid",
        "@capnp-cpp//src/kj/compat:kj-brotli",
        "@capnp-cpp//src/kj/compat:kj-gzip",
        "@nbytes",
        "@simdutf",
    ],
    visibility = ["//visibility:public"],
    deps = [
        ":actor",
        ":actor-id",
        ":actor-storage_capnp",
        ":cdp_capnp",
        ":container_capnp",
        ":frankenvalue",
        ":io-gate",
        ":io-helpers",
        ":limit-enforcer",
        ":observer",
        ":supported-compatibility-date",
        ":trace",
        ":worker-interface",
        ":worker-source",
        "//src/rust/cxx-integration",
        "//src/workerd/api:analytics-engine_capnp",
        "//src/workerd/api:deferred-proxy",
        "//src/workerd/api:encoding",
        "//src/workerd/api:fuzzilli",
        "//src/workerd/api:hibernation-event-params",
        "//src/workerd/api:url",
        "//src/workerd/jsg",
        "//src/workerd/jsg:inspector",
        "//src/workerd/jsg:script",
        "//src/workerd/util:checked-queue",
        "//src/workerd/util:exception",
        "//src/workerd/util:header-validation",
        "//src/workerd/util:immediate-crash",
        "//src/workerd/util:ring-buffer",
        "//src/workerd/util:small-set",
        "//src/workerd/util:sqlite",
        "//src/workerd/util:strong-bool",
        "@capnp-cpp//src/capnp:capnp-rpc",
        "@capnp-cpp//src/capnp/compat:http-over-capnp",
        "@capnp-cpp//src/kj:kj-async",
        "@ncrypto",
        "@ssl",
    ],
)

wd_cc_library(
    name = "worker-modules",
    srcs = ["worker-modules.c++"],
    hdrs = ["worker-modules.h"],
    implementation_deps = [
        "//src/pyodide:pyodide_static",
        "//src/workerd/api:pyodide",
        "//src/workerd/api/node",
    ],
    visibility = ["//visibility:public"],
    deps = [
        ":io",
        "//src/pyodide:python-entrypoint",
        "//src/workerd/api:commonjs",
        "//src/workerd/api:rtti",
        "//src/workerd/jsg",
        "//src/workerd/util:strong-bool",
    ],
)

wd_cc_library(
    name = "bundle-fs",
    srcs = ["bundle-fs.c++"],
    hdrs = ["bundle-fs.h"],
    visibility = ["//visibility:public"],
    deps = [
        ":io",
    ],
)

wd_cc_library(
    name = "promise-wrapper",
    hdrs = ["promise-wrapper.h"],
    visibility = ["//visibility:public"],
    deps = [
        ":io",
        "//src/workerd/jsg",
    ],
)

wd_cc_library(
    name = "worker-source",
    hdrs = ["worker-source.h"],
    visibility = ["//visibility:public"],
    deps = [
        "//src/rust/cxx-integration",
        "@capnp-cpp//src/capnp",
    ],
)

# TODO(cleanup): Split this up further.
wd_cc_library(
    name = "actor",
    srcs = [
        "actor-cache.c++",
        "actor-sqlite.c++",
        "actor-storage.c++",
    ],
    hdrs = [
        "actor-cache.h",
        "actor-sqlite.h",
        "actor-storage.h",
    ],
    visibility = ["//visibility:public"],
    deps = [
        ":actor-storage_capnp",
        ":io-gate",
        ":trace",
        "//src/workerd/jsg:exception",
        "//src/workerd/util:autogate",
        "//src/workerd/util:duration-exceeded-logger",
        "//src/workerd/util:sqlite",
        "@capnp-cpp//src/capnp:capnp-rpc",
        "@capnp-cpp//src/kj:kj-async",
    ],
)

wd_cc_library(
    name = "frankenvalue",
    srcs = ["frankenvalue.c++"],
    hdrs = ["frankenvalue.h"],
    visibility = ["//visibility:public"],
    deps = [
        ":frankenvalue_capnp",
        "//src/workerd/jsg",
        "@capnp-cpp//src/capnp:capnpc",
    ],
)

wd_cc_library(
    name = "trace",
    srcs = ["trace.c++"],
    hdrs = ["trace.h"],
    implementation_deps = [
        "//src/workerd/util:entropy",
        "//src/workerd/util:thread-scopes",
    ],
    visibility = ["//visibility:public"],
    deps = [
        ":trace_capnp",
        ":worker-interface_capnp",
        "//src/workerd/jsg:memory-tracker",
        "//src/workerd/util:own-util",
        "@capnp-cpp//src/capnp:capnp-rpc",
        "@capnp-cpp//src/capnp:capnpc",
        "@capnp-cpp//src/kj/compat:kj-http",
        "@ssl",
    ],
)

wd_cc_library(
    name = "observer",
    srcs = ["observer.c++"],
    hdrs = ["observer.h"],
    implementation_deps = [
        ":worker-interface",
    ],
    visibility = ["//visibility:public"],
    deps = [
        ":features_capnp",
        ":trace",
        "//src/workerd/jsg:observer",
        "//src/workerd/util:sqlite",
    ],
)

wd_cc_library(
    name = "io-gate",
    srcs = ["io-gate.c++"],
    hdrs = ["io-gate.h"],
    visibility = ["//visibility:public"],
    deps = [
        "@capnp-cpp//src/kj",
        "@capnp-cpp//src/kj:kj-async",
    ],
)

wd_cc_library(
    name = "limit-enforcer",
    hdrs = ["limit-enforcer.h"],
    visibility = ["//visibility:public"],
    deps = [
        ":outcome_capnp",
        "//src/workerd/jsg",
    ],
)

wd_cc_library(
    name = "worker-entrypoint",
    srcs = ["worker-entrypoint.c++"],
    hdrs = ["worker-entrypoint.h"],
    implementation_deps = [
        "//src/workerd/util:perfetto",
        "//src/workerd/util:strings",
    ],
    visibility = ["//visibility:public"],
    deps = [
        ":io",
    ],
)

wd_cc_library(
    name = "worker-interface",
    srcs = ["worker-interface.c++"],
    hdrs = ["worker-interface.h"],
    visibility = ["//visibility:public"],
    deps = [
        ":frankenvalue_capnp",
        ":trace",
        ":worker-interface_capnp",
        "//src/workerd/util",
        "@capnp-cpp//src/capnp:capnp-rpc",
        "@capnp-cpp//src/capnp:capnpc",
        "@capnp-cpp//src/capnp/compat:http-over-capnp",
    ],
)

wd_cc_library(
    name = "actor-id",
    hdrs = ["actor-id.h"],
    visibility = ["//visibility:public"],
    deps = ["@capnp-cpp//src/kj"],
)

genrule(
    name = "trimmed-supported-compatibility-date-gen",
    srcs = ["supported-compatibility-date.txt"],
    outs = ["trimmed-supported-compatibility-date.txt"],
    cmd = "tr -d '\n' < $(location supported-compatibility-date.txt) > $(location trimmed-supported-compatibility-date.txt)",
    cmd_ps = "(Get-Content $(location supported-compatibility-date.txt) -Raw -Encoding Ascii).TrimEnd() | Set-Content $(location trimmed-supported-compatibility-date.txt) -NoNewLine -Encoding Ascii",
    visibility = ["//visibility:public"],
)

# Newest compatibility date that can safely be set using code compiled from this repo. Trying to
# run a Worker with a newer compatibility date than this will fail.
#
# This should be updated to the current date on a regular basis. The reason this exists is so that
# if you build an old version of the code and try to run a new Worker with it, you get an
# appropriate error, rather than have the code run with the wrong compatibility mode.
#
# Note that the production Cloudflare Workers upload API always accepts any date up to the current
# date regardless of this constant, on the assumption that Cloudflare is always running the latest
# version of the code. This constant is more to protect users who are self-hosting the runtime and
# could be running an older version.
wd_cc_embed(
    name = "supported-compatibility-date",
    src = ":trimmed-supported-compatibility-date.txt",
    base_name = "supported-compatibility-date",
)

wd_capnp_library(src = "cdp.capnp")

wd_capnp_library(
    src = "worker-interface.capnp",
    deps = [
        ":frankenvalue_capnp",
        ":outcome_capnp",
        ":script-version_capnp",
        ":trace_capnp",
        "@capnp-cpp//src/capnp/compat:http-over-capnp_capnp",
    ],
)

wd_capnp_library(src = "actor-storage.capnp")

wd_capnp_library(src = "outcome.capnp")

wd_capnp_library(src = "script-version.capnp")

wd_capnp_library(src = "trace.capnp")

wd_capnp_library(src = "compatibility-date.capnp")

wd_capnp_library(src = "features.capnp")

wd_capnp_library(src = "frankenvalue.capnp")

wd_capnp_library(
    src = "container.capnp",
    deps = [
        "@capnp-cpp//src/capnp/compat:byte-stream_capnp",
    ],
)

kj_test(
    src = "io-gate-test.c++",
    deps = [
        ":io-gate",
    ],
)

kj_test(
    src = "actor-cache-test.c++",
    deps = [
        ":actor",
        ":io-gate",
        "//src/workerd/util:test",
        "//src/workerd/util:test-util",
    ],
)

kj_test(
    src = "actor-sqlite-test.c++",
    deps = [
        ":actor",
        ":io-gate",
        "//src/workerd/util:test",
        "//src/workerd/util:test-util",
    ],
)

kj_test(
    src = "promise-wrapper-test.c++",
    deps = [
        ":io",
        ":promise-wrapper",
    ],
)

kj_test(
    src = "compatibility-date-test.c++",
    deps = [
        ":io",
        "@capnp-cpp//src/capnp:capnpc",
    ],
)

kj_test(
    src = "observer-test.c++",
    deps = [
        ":observer",
        "//src/workerd/io:worker-interface",
        "//src/workerd/util:strings",
        "@capnp-cpp//src/capnp:capnpc",
    ],
)

kj_test(
    src = "trace-test.c++",
    deps = [
        ":trace",
        "//src/workerd/util:thread-scopes",
    ],
)

kj_test(
    src = "frankenvalue-test.c++",
    deps = [
        ":frankenvalue",
    ],
)

kj_test(
    src = "worker-fs-test.c++",
    deps = [
        ":io",
    ],
)

wd_test(
    src = "io-context-test.wd-test",
    args = ["--experimental"],
    data = ["io-context-test.js"],
)

kj_test(
    src = "bundle-fs-test.c++",
    deps = [
        ":bundle-fs",
        ":io",
        "//src/workerd/tests:test-fixture",
    ],
)
